/***************************************************************************
 *            tetris.c
 *
 *  Sa Januar 21 13:02:25 2012
 *  Copyright  2012  ich
 *  <user@host>
 ****************************************************************************/
/*
 * tetris.c
 *
 * Copyright (C) 2012 - ich
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */


#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "option.h"
#include "tetris.h"

int TFN_InitTetris (TFN_Contex_p contex)
{
    fprintf (log_f, "%s: Funktion: %s wurde aufgerufen\n", __TIME__, __FUNCTION__);

    int test;

    TFN_Contex_p tmp_con = (TFN_Contex_p) malloc (sizeof(TFN_Contex_t));
    if (tmp_con == NULL)
    {
        fprintf (log_f, "\tKonnte keinen Speicher für den TFN_Contex reservieren!");
        return -1;
    }

    tmp_con->spfeld = (TFN_Feld_p) malloc (sizeof(TFN_Feld_t));
    if (tmp_con->spfeld == NULL)
    {
        fprintf(log_f, "\tKonnte keinen Speicher für das Spielfeld, des angeforderten TFN_Contextes reservieren!");
        return -1;
    }

    test = TFN_NeuerStein(tmp_con);
    if (test != 0)
    {
        return -1;
    }
    tmp_con->level = 1;
    tmp_con->punkte = 0;
    tmp_con->zeit = NULL;

    return 0;
}



TFN_Stein_p createStein (void)
{
    int type2;

    TFN_Stein_p tmp1 = (TFN_Stein_p) malloc (sizeof(TFN_Stein_t));
	if (tmp1 == NULL)
	{
        fprintf (log_f, "\tKonnte keinen Speicher für einen neuen Spielstein reservieren!\n");
        return NULL;
    }
    srand (time(NULL));
    type2 = rand ()%7;
    type2++;
    tmp1->drehung = 0;
    tmp1->block->type = type2;
    tmp1->type = type2;
    switch (type2)
    {
    case 1:
        tmp1->block[0].x = 9;
        tmp1->block[0].y = 3;
        tmp1->block[1].x = 10;
        tmp1->block[1].y = 3;
        tmp1->block[2].x = 9;
        tmp1->block[2].y = 4;
        tmp1->block[3].x = 10;
        tmp1->block[3].y = 4;
        break;
    case 2:
        tmp1->block[0].x = 9;
        tmp1->block[0].y = 1;
        tmp1->block[1].x = 9;
        tmp1->block[1].y = 2;
        tmp1->block[2].x = 9;
        tmp1->block[2].y = 3;
        tmp1->block[3].x = 9;
        tmp1->block[3].y = 4;
        break;
    case 3:
        tmp1->block[0].x = 8;
        tmp1->block[0].y = 3;
        tmp1->block[1].x = 9;
        tmp1->block[1].y = 3;
        tmp1->block[2].x = 10;
        tmp1->block[2].y = 3;
        tmp1->block[3].x = 9;
        tmp1->block[3].y = 4;
        break;
    case 4:
        tmp1->block[0].x = 8;
        tmp1->block[0].y = 3;
        tmp1->block[1].x = 9;
        tmp1->block[1].y = 3;
        tmp1->block[2].x = 10;
        tmp1->block[2].y = 3;
        tmp1->block[3].x = 10;
        tmp1->block[3].y = 4;
        break;
    case 5:
        tmp1->block[0].x = 8;
        tmp1->block[0].y = 3;
        tmp1->block[1].x = 9;
        tmp1->block[1].y = 3;
        tmp1->block[2].x = 10;
        tmp1->block[2].y = 3;
        tmp1->block[3].x = 8;
        tmp1->block[3].y = 4;
        break;
    case 6:
        tmp1->block[0].x = 8;
        tmp1->block[0].y = 3;
        tmp1->block[1].x = 9;
        tmp1->block[1].y = 3;
        tmp1->block[2].x = 9;
        tmp1->block[2].y = 4;
        tmp1->block[3].x = 10;
        tmp1->block[3].y = 4;
        break;
    case 7:
        tmp1->block[0].x = 9;
        tmp1->block[0].y = 3;
        tmp1->block[1].x = 10;
        tmp1->block[1].y = 3;
        tmp1->block[2].x = 8;
        tmp1->block[2].y = 4;
        tmp1->block[3].x = 9;
        tmp1->block[3].y = 4;
        break;
    }
	
    return tmp1;
}





int TFN_NeuerStein (TFN_Contex_p contex)
{
    fprintf (log_f, "%s: Funktion: %s wurde aufgerufen\n", __TIME__, __FUNCTION__);


    if (contex->nextstein == NULL)
    {
        contex->nextstein = createStein ();
    }
    if (contex->spstein != NULL)
    {
        free (contex->spstein);
    }

    contex->spstein = contex->nextstein;
    contex->nextstein = createStein();
    return 0;
}


TFN_Stein_p CPStein (TFN_Stein_p st)
{//TODO Testen ob das wirklich so geht!!!!!
    fprintf (log_f, "%s: Funktion: %s wurde aufgerufen\n", __TIME__, __FUNCTION__);

    TFN_Stein_p stein = (TFN_Stein_p) malloc (sizeof(TFN_Stein_t));
    if (stein == NULL)
    {
        fprintf (log_f, "\tKonnte keinen Speicher für den neuen Stein reservieren!");
        return NULL;
    }

    (*stein->block) = (*st->block);
    stein->drehung = st->drehung;

    return stein;
}


int TFN_MVStein (int x, int y, TFN_Contex_p contex)
{
    TFN_Stein_p stein;
    int xx;

    stein = CPStein (contex->spstein);

    for (xx = 0; xx < 4; xx++)
    {
        stein->block[xx].x += x;
        stein->block[xx].y += y;
    }

    xx = TFN_Pruefekollision (stein, contex->spfeld);
//TODO Reihe entfernen und ende prüfen!!
    if (xx != 0)
        return -1;

    contex->spstein = CPStein(stein);
    return 0;
}


int TFN_DreheStein (TFN_Contex_p contex)
{
    TFN_Stein_p stein;
	int coll;
	
	
    stein = CPStein(contex->spstein);

    switch (stein->type)
    {
        case 1:
            return 0;
            break;

        case 2:
            if (stein->drehung == 0)
            {
                stein->block[0].x += 2;
                stein->block[0].y -= 2;
                stein->block[1].x += 1;
                stein->block[1].y -= 1;
                stein->block[3].x -= 1;
                stein->block[3].y += 1;
                stein->drehung = 1;
            }
            else
            {
                stein->block[0].x -= 2;
                stein->block[0].y += 2;
                stein->block[1].x -= 1;
                stein->block[1].y += 1;
                stein->block[3].x += 1;
                stein->block[3].y -= 1;
                stein->drehung = 0;
            }
            break;
        case 3:
            if (stein->drehung == 0)
            {
                stein->block[0].x += 1;
                stein->block[0].y -= 1;
                stein->block[2].x -= 1;
                stein->block[2].y -= 1;
                stein->block[3].x -= 1;
                stein->block[3].y += 1;
                stein->drehung = 1;
            }
            else if (stein->drehung == 1)
            {
                stein->block[0].x += 1;
                stein->block[0].y += 1;
                stein->block[2].x += 1;
                stein->block[2].y -= 1;
                stein->block[3].x -= 1;
                stein->block[3].y -= 1;
                stein->drehung = 2;
            }
            else if (stein->drehung == 2)
            {
                stein->block[0].x -= 1;
                stein->block[0].y += 1;
                stein->block[2].x += 1;
                stein->block[2].y += 1;
                stein->block[3].x += 1;
                stein->block[3].y -= 1;
                stein->drehung = 3;
            }
            else if (stein->drehung == 3)
            {
                stein->block[0].x -= 1;
                stein->block[0].y -= 1;
                stein->block[2].x -= 1;
                stein->block[2].y += 1;
                stein->block[3].x += 1;
                stein->block[3].y += 1;
                stein->drehung = 0;
            }
            break;
        case 4:
            if (stein->drehung == 0)
            {
                stein->block[0].x += 1;
                stein->block[0].y -= 1;
                stein->block[2].x -= 1;
                stein->block[2].y += 1;
                stein->block[3].y -= 2;
                stein->drehung = 1;
            }
            else if (stein->drehung == 1)
            {
                stein->block[0].x += 1;
                stein->block[0].y += 1;
                stein->block[2].x -= 1;
                stein->block[2].y -= 1;
                stein->block[3].x += 2;
                stein->drehung = 2;
            }
            else if (stein->drehung == 2)
            {
                stein->block[0].x -= 1;
                stein->block[0].y += 1;
                stein->block[2].x += 1;
                stein->block[2].y -= 1;
                stein->block[3].y += 2;
                stein->drehung = 3;
            }
            else if (stein->drehung == 3)
            {
                stein->block[0].x -= 1;
                stein->block[0].y -= 1;
                stein->block[2].x += 1;
                stein->block[2].y += 1;
                stein->block[3].x -= 2;
                stein->drehung = 0;
            }
            break;

        case 5:
            if (stein->drehung == 0)
            {
                stein->block[0].x += 1;
                stein->block[0].y -= 1;
                stein->block[2].x -= 1;
                stein->block[2].y += 1;
                stein->block[3].x -= 2;
                stein->drehung = 1;
            }
            else if (stein->drehung == 1)
            {
                stein->block[0].x += 1;
                stein->block[0].y += 1;
                stein->block[2].x -= 1;
                stein->block[2].y -= 1;
                stein->block[3].y -= 2;
                stein->drehung = 2;
            }
            else if (stein->drehung == 2)
            {
                stein->block[0].x -= 1;
                stein->block[0].y += 1;
                stein->block[2].x += 1;
                stein->block[2].y -= 1;
                stein->block[3].x += 2;
                stein->drehung = 3;
            }
            else if (stein->drehung == 3)
            {
                stein->block[0].x -= 1;
                stein->block[0].y -= 1;
                stein->block[2].x += 1;
                stein->block[2].y += 1;
                stein->block[3].y += 2;
                stein->drehung = 0;
            }
            break;

        case 6:
            if (stein->drehung == 0)
            {
                stein->block[0].x += 1;
                stein->block[0].y -= 1;
                stein->block[2].x -= 1;
                stein->block[2].y -= 1;
                stein->block[3].x -= 2;
                stein->drehung = 1;
            }
            else if (stein->drehung == 1)
            {
                stein->block[0].x -= 1;
                stein->block[0].y += 1;
                stein->block[2].x += 1;
                stein->block[2].y += 1;
                stein->block[3].x += 2;
                stein->drehung = 0;
            }
            break;

        case 7:
            if (stein->drehung == 0)
            {
                stein->block[1].x -= 1;
                stein->block[1].y += 1;
                stein->block[2].y -= 2;
                stein->block[3].x -= 1;
                stein->block[3].y -= 1;
                stein->drehung = 1;
            }
            else if (stein->drehung == 1)
            {
                stein->block[1].x += 1;
                stein->block[1].y -= 1;
                stein->block[2].y += 2;
                stein->block[3].x += 1;
                stein->block[3].y += 1;
                stein->drehung = 0;
            }
            break;

        default:
            return -1;
    }

	coll = TFN_Pruefekollision	(stein, contex->spfeld);
	if ( coll == 0 )
	{
		contex->spstein = CPStein (stein);
		return 0;
	}

	return -1;
}


/*
 * Rückgabewerte sind:
 * 	0 = keine kollision
 *  1 = untererrand
 *  2 = linker rand
 *  3 = rechter rand
 *  4 = spielfeld
 */
int TFN_Pruefekollision (TFN_Stein_p stein, TFN_Feld_p feld)
{
	int x;

	for (x = 0; x < 4; x++)
	{
		if (stein->block[x].x < 5 )
			return 2;
		if (stein->block[x].x > 15 )
			return 3;
		if (stein->block[x].y > 30 )
			return 1;

		if (feld->feld[stein->block[x].x][stein->block[x].y] != 0)
			return 4;
	}
	return 0;
}


int TFN_PruefeZeile (TFN_Contex_p contex)
{
	int x, y;

	for (y = 5; y < 30; y++)
	{
		for (x = 5; x < 15; x++)
		{
			if (contex->spfeld->feld[x][y] == 0)
			{
				return -1;
			}
			if (x == 14)
			{
				TFN_RMZeile (y, contex);
			}
		}
	}
	return 0;
}

TFN_Feld_p CP_Feld (TFN_Feld_p feld)
{
	TFN_Feld_p tmp = (TFN_Feld_p) malloc (sizeof(TFN_Feld_t));

	int x, y;

	for (x = 0; x < 20; x++)
	{
		for (y = 0; y < 35; y++)
		{
			tmp->feld[x][y] = feld->feld[x][y];
		}
	}
	return 0;
}

int TFN_RMZeile (int zeile, TFN_Contex_p contex)
{
	TFN_Feld_p pfeld = CP_Feld (contex->spfeld);

	int x, y, yy;
	
	for (y = 30; y > 4 ; y--)
	{
		for (x = 0; x < 20; x++)
		{
			yy = y;
			if (x == 19)
				break;

			if ( y <= zeile )
			{
				yy--;
			}
			contex->spfeld->feld[x][y] = pfeld->feld[x][yy];

		}
	}
}


int TFN_PruefeEnde (TFN_Contex_p contex)
{
	return 0;
}


int TFN_BlitStein (TFN_Contex_p contex)
{
	int x;

	for (x = 0; x < 4; x++)
	{
		contex->spfeld->feld[contex->spstein->block[x].x][contex->spstein->block[x].y] = contex->spstein->block[x].type;
	}
	return 0;
}
